package com.xiyuan.smartutils.client.ws.core;

import com.xiyuan.smartutils.client.ws.WebSocketPacket;
import com.xiyuan.smartutils.client.exception.WebSocketException;

import java.nio.ByteBuffer;
import java.util.EnumMap;
import java.util.EnumSet;

/**
 * The class WebSocketPacketParser
 *
 * @author xiyuan 2022-07-10 @version 1.0.0 新建或整理
 */
public abstract class WebSocketPacketResolver {
    public abstract WebSocketPacket resolve(ByteBuffer buf) throws WebSocketException;
    public abstract void reset();
    
    /**
     * The state.
     */
    private volatile PacketState state = PacketState.DONE;
    
    /**
     * State.
     *
     * @return the state
     */
    protected PacketState state() {
        return state;
    }
    
    protected PacketState stateTo(PacketState to) {
        if (state.canTransitionTo(to)) {
            PacketState old = state;
            state = to;
            return old;
        }
        else {
            throw new IllegalStateException("Couldn't transtion from " + state + " to " + to);
        }
    }
    
  
    public enum PacketState {
        /**
         * The HEADER.
         */
        HEADER,
        /**
         * The FRAME.
         */
        FRAME,
        /**
         * The DONE.
         */
        DONE;
        
        /**
         * The state map.
         */
        private static EnumMap<PacketState, EnumSet<PacketState>> stateMap = new EnumMap<PacketState, EnumSet<PacketState>>(
                PacketState.class);
        
        static {
            stateMap.put(HEADER, EnumSet.of(PacketState.FRAME));
            stateMap.put(FRAME, EnumSet.of(PacketState.DONE));
            stateMap.put(DONE, EnumSet.of(PacketState.HEADER));
        }
        
        /**
         * Can transition to.
         *
         * @param state the state
         * @return true, if successful
         */
        boolean canTransitionTo(PacketState state) {
            EnumSet<PacketState> set = stateMap.get(this);
            if (set == null) {return false;}
            return set.contains(state);
        }
    }
    
}
